package ro.msg.office.ticketmanager.back.bean;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;

import ro.msg.office.entities.Ticket;
import ro.msg.office.entities.User;
import ro.msg.office.ticketmanager.DO.DepartmentDO;
import ro.msg.office.ticketmanager.DO.TicketDO;
import ro.msg.office.ticketmanager.DO.UserDO;
import ro.msg.office.ticketmanager.back.ifc.TicketManager;
import ro.msg.office.ticketmanager.back.ifc.UserManager;

/********************************************************
*@Stateless session bean instances can be pooled and 
	may be shared between clients.When a client 
	invokes a method in a stateless session bean,the
	container either creates a new instance for the 
	client or assigns one from the bean. The instance
	is returned to the pool after use.
*@TransactionManagement the container should manage 
	transactions on the bean’s behalf
********************************************************/

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TicketManagerBean implements TicketManager {
	
	Logger logger = Logger.getLogger(TicketManagerBean.class);
	/******************************************
		Injects EntityManager instance 
	 ******************************************/
	@PersistenceContext(unitName = "TM_PU")
	private EntityManager em;
	@EJB
	private UserManager userEJB;

	/**
	 * Map Ticket to TicketDO and return list of TicketDO 
	 * @param Set<Ticket> t
	 * @return Set<TicketDO>
	 */
	public Set<TicketDO> mapTickets(Set<Ticket> t) {
		Iterator<Ticket> it = t.iterator();
		Set<TicketDO> tickets = new HashSet<TicketDO>();
		while (it.hasNext()) {
			Ticket ticket = it.next();
			TicketDO ticketDO = ticket.mapTicketToDO(ticket);
			ticketDO.setStatusString();
			tickets.add(ticketDO);
		}
		return tickets;
	}

	/**
	 * Find User by a Ticket ID. Return User 
	 * @param id
	 * @return User
	 */
	public User findUserByTicketId(Long id) {
		Query query = em.createNamedQuery("User.findById");
		query.setParameter("id", id);
		if (query.getResultList().isEmpty())
			return null;
		else {
			List<User> users = query.getResultList();
			return users.get(0);
		}
	}

	/**
	 * Find UserDo by a TicketID. Return UserDO 
	 * @param id
	 * @return UserDO
	 */
	public UserDO findUserDOByTicketId(Long id) {
		User user = findUserByTicketId(id);
		UserDO userDO = userEJB.mapUserToDO(user);
		return userDO;
	}

	/**
	 * Create a Ticket by TicketDo and return true or false
	 * @param ticketDO
	 * @return boolean
	 */
	public boolean createTicket(TicketDO ticketDO) {
		boolean created = false;
		Ticket ticket = new Ticket();
		ticket.setApprovalDate(ticketDO.getApprovalDate());
		ticket.setCreationDate(ticketDO.getCreationDate());
		ticket.setEndTime(ticketDO.getEndTime());
		ticket.setDescription(ticketDO.getDescription());
		ticket.setRejected(ticketDO.getRejected());
		ticket.setStartTime(ticketDO.getStartTime());
		ticket.setStatus(ticketDO.getStatus());
		ticket.setUser(findUserByTicketId(ticketDO.getUserID()));
		em.persist(ticket);
		created = true;
		logger.info("Ticket created with info: " + ticket.getTicketId());
		return created;
	}

	/**
	 * Get UserName by UserId from TicketDO
	 * @param ticketDO
	 * @return TicketDO
	 */
	public TicketDO getUserNameByUserId(TicketDO ticketDO) {
		Query query = em.createNamedQuery("User.findNameById");
		query.setParameter("id", ticketDO.getUserID());
		if (query.getResultList().isEmpty())
			return null;
		else {
			List<Ticket> tickets = query.getResultList();
			Ticket ticket = tickets.get(0);
			return ticket.mapTicketToDO(ticket);
		}
	}

	/**
	 * Get all tickets by departmentID
	 * @param departmentDO
	 * @return Set<TicketDO>
	 */
	public Set<TicketDO> getTicketsByDepartment(DepartmentDO departmentDO) {
		Query query = em.createNamedQuery("Ticket.findAllByDepartment");
		query.setParameter("department", departmentDO.getId());

		if (query.getResultList().isEmpty())
			return (new HashSet<TicketDO>());
		else {
			List<Ticket> tickets = query.getResultList();
			Set<Ticket> ticketsAll = new HashSet<Ticket>(tickets);
			return mapTickets(ticketsAll);
		}
	}
	
	/**
	 * Get all tickets by ticketID
	 * @param ticketDO
	 * @return TicketDO
	 */
	public TicketDO getTicketInfo(TicketDO ticketDO) {
		Query query = em.createNamedQuery("Ticket.findAllById");
		query.setParameter("id", ticketDO.getTicketId());
		if (query.getResultList().isEmpty())
			return null;
		else {
			List<Ticket> tickets = query.getResultList();
			Ticket ticket = tickets.get(0);
			return ticket.mapTicketToDO(ticket);
		}
	}
	
	/**
	 * Receive tickets for userDO by username and password. 
	 * The method use mapTickets
	 * @param UserDO
	 * @return Set<TicketDO>
	 */
	public Set<TicketDO> receiveTickets(UserDO userDO) {
		User user = userEJB.findUserByNameAndPassword(userDO.getUsername(),
				userDO.getPassword());
		Query query = em.createNamedQuery("Ticket.findAllByUser");
		query.setParameter("user", user);
		List<Ticket> tickets = query.getResultList();
		Set<Ticket> ticketSet = new HashSet<Ticket>(tickets);
		if (!ticketSet.isEmpty()){
			return mapTickets(ticketSet);
		}
		else
			return new HashSet<TicketDO>();
	}

	/**
	 * Update ticket by TicketDO
	 * @param ticketDO
	 * @return boolean
	 */
	public boolean updateTicket(TicketDO ticketDO) {
		boolean updated = false;
		Ticket ticket = em.find(Ticket.class, ticketDO.getTicketId());
		logger.info("Updating ticket with info: " + ticket.getTicketId());
		logger.info("Old values:" + ticket.getDescription() + " " + ticket.getStatus() + " " + ticket.getCreationDate());
		ticket.setDescription(ticketDO.getDescription());
		ticket.setStatus(ticketDO.getStatus());
		ticket.setCreationDate(ticketDO.getCreationDate());
		logger.info("New values:" + ticket.getDescription() + " " + ticket.getStatus() + " " + ticket.getCreationDate());
		updated = true;
		return updated;
	}
	
	/**
	 * Update ticket by admin
	 * @param ticketDO
	 * @return boolean
	 */
	public boolean updateTicketByAdmin(TicketDO ticketDO) {
		boolean updated = false;
		Ticket ticket = em.find(Ticket.class, ticketDO.getTicketId());
		logger.info("Updating ticket with info: " + ticket.getTicketId());
		logger.info("Old values:" + ticket.getApprovalDate() + " " + ticket.getStatus() + " " + ticket.getRejected());
		ticket.setApprovalDate(ticketDO.getApprovalDate());
		ticket.setStatus(ticketDO.getStatus());
		ticket.setRejected(ticketDO.getRejected());
		logger.info("New values:" + ticket.getApprovalDate() + " " + ticket.getStatus() + " " + ticket.getRejected());
		updated = true;
		return updated;
	}

}
